﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Xml.Serialization;
using System.Diagnostics;

namespace DirectorySynchronizer
{
    public partial class MainForm : Form, IProgressDisplay
    {
        private bool showingadvancedoptions = false;
        private State currentstate = State.OptionsSetup;
        private bool[] EnableDisableIgnoreSUBcontrols = null;
        private Control[] EnableDisableIgnoreControls = null;
        private HTMLDisplayForm childhtmldisplayform = null;
        private DirSynchronizer directorysynchronizer = null;

        public MainForm()
        {
            InitializeComponent();
            ctrlAdvancedOptionsOverlay.Location = new Point(12, 101);
            ctrlAdvancedOptionsOverlay.Size = new Size(775, 306);
            ctrlAdvancedOptionsOverlay.Anchor = AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Left;
        }
        public MainForm(DirSyncOptions argDSO)
            : this()
        {
            LoadOptionsSetupFromObject(argDSO);
        }
        public MainForm(string argSourcePath, string argTargetPath)
            : this()
        {
            textBoxSourceDir.Text = argSourcePath;
            textBoxTargetDir.Text = argSourcePath;
        }
        private void MainForm_Load(object sender, EventArgs e)
        {
            timerInputVerification.Enabled = false;
            EnableDisableIgnoreControls = new Control[] { ctrlAdvancedOptionsOverlay, buttonClose, this };
            EnableDisableIgnoreSUBcontrols = new bool[] { true, true, false };
            ctrlAdvancedOptionsOverlay.ParentMainForm = this;
            UpdateRefreshFormControls();
        }
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (currentstate == State.Synchronizing)
            {
                DialogResult dr = MessageBox.Show("Synchronization in progress, are you sure you want to cancel and exit?", "Directory Synchronizer: Confirm Cancel and Exit", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (dr == System.Windows.Forms.DialogResult.Yes)
                {
                    if (directorysynchronizer != null) { directorysynchronizer.Cancel(); }
                }
                else
                {
                    e.Cancel = true;
                }
            }
        }

        private void advancedoptionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            showingadvancedoptions = true;
            dataGridViewSyncResults.ColumnHeadersVisible = false;
            RecursiveEnableDisable(this, false);
            ctrlAdvancedOptionsOverlay.Visible = true;
        }
        private void saveSettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.AddExtension = false;
            sfd.CheckFileExists = false;
            sfd.CheckPathExists = true;
            sfd.CreatePrompt = false;
            sfd.DefaultExt = DirSyncOptions.OptsFileExt;
            sfd.Filter = "DirSync Options (*." + DirSyncOptions.OptsFileExt + ")|*." + DirSyncOptions.OptsFileExt;
            sfd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            sfd.OverwritePrompt = true;
            sfd.ShowHelp = false;
            sfd.Title = "Directory Synchronizer: Select File for Option Settings Export";
            if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                GetCurrentOptionsSetup().SaveOptionSettingsToFile(sfd.FileName);
            }
        }
        private void loadSetupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DirSyncOptions returndirsyncoptions = DirSyncOptions.ImportOptionsSettings();
            if (returndirsyncoptions == null) { return; }
            LoadOptionsSetupFromObject(returndirsyncoptions);
        }
        private void exportResultDataToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.AddExtension = true;
                sfd.CheckPathExists = true;
                sfd.CreatePrompt = false;
                sfd.DefaultExt = "dsd";
                sfd.FileName = "DirSyncData1";
                sfd.Filter = "Dir. Sync. Data (*.dsd)|*.dsd";
                sfd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                sfd.OverwritePrompt = true;
                sfd.ShowHelp = false;
                sfd.SupportMultiDottedExtensions = true;
                sfd.Title = "Directory Synchronizer: Select Options Setup Save File";
                if (sfd.ShowDialog() == DialogResult.OK)
                {
                    try
                    {
                        XmlSerializer xs = new XmlSerializer((dataGridViewSyncResults.DataSource).GetType(), Program.OperantNamespace);
                        StreamWriter sw = new StreamWriter(sfd.FileName, false);
                        xs.Serialize(sw, (dataGridViewSyncResults.DataSource));
                        sw.Close();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("DirectorySynchronizer eRDTSMI1: " + ex.Message);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("DirectorySynchronizer eRDTSMI2: " + ex.Message);
            }
        }
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }
        private void helpManualToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (childhtmldisplayform != null) { return; }
            Screen targetscreen = Screen.FromHandle(this.Handle);
            childhtmldisplayform = new HTMLDisplayForm("DirectorySynchronizer.Resources.usermanual.html", targetscreen, this);
            childhtmldisplayform.Text = "Directory Synchronizer " + Program.VersionNumber + ": Help Manual";
            childhtmldisplayform.Show();
            this.Left = childhtmldisplayform.Right + 10;
        }
        private void licenseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OnSpaceSI.LicenseDisplayForm ldf = new OnSpaceSI.LicenseDisplayForm();
            ldf.ShowForReview();
            ldf.ShowDialog();
        }
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Directory Synchronizer" + Program.VersionNumber + "\r\nCopyright 2014 Rich W.", "About Directory Synchronizer", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void buttonBrowseForDir1_Click(object sender, EventArgs e)
        {
            BrowseFolder(textBoxSourceDir, "Browse For Origin Folder");
        }
        private void buttonBrowseForDir2_Click(object sender, EventArgs e)
        {
            BrowseFolder(textBoxTargetDir, "Select Target Folder");
        }
        private void BrowseFolder(TextBox target_textbox, string browsertitle)
        {
            FolderBrowserDialog fbd = new FolderBrowserDialog();
            fbd.Description = browsertitle;
            fbd.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
            if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                target_textbox.Text = fbd.SelectedPath;
            }
            CheckIfSyncReady(null, null);
        }

        private void buttonSynchronize_Click(object sender, EventArgs e)
        {
            directorysynchronizer = new DirSynchronizer(GetCurrentOptionsSetup(), this);
            ThreadStart threadstart = new ThreadStart(directorysynchronizer.StartDirectorySynchronization);
            Thread syncthread = new Thread(threadstart);
            currentstate = State.Synchronizing;
            syncthread.Start();
            UpdateRefreshFormControls();
        }
        private void buttonCancelSync_Click(object sender, EventArgs e)
        {
            if (directorysynchronizer != null) { directorysynchronizer.Cancel(); }
            currentstate = State.SynchronizationCanceled;
            UpdateRefreshFormControls();
        }
        private void buttonClose_Click(object sender, EventArgs e)
        {
            Close();
        }
        public void buttonCancel_Click(object sender, EventArgs e)
        {
            if (directorysynchronizer != null) { directorysynchronizer.Cancel(); }
        }
        private void buttonResetSynchronizer_Click(object sender, EventArgs e)
        {
            dataGridViewSyncResults.DataSource = null;
            currentstate = State.OptionsSetup;
            UpdateRefreshFormControls();
            CheckIfSyncReady(null, null);
        }

        private void textBoxDir_DragOver(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            { e.Effect = DragDropEffects.Copy; }
            else
            { e.Effect = DragDropEffects.None; }
        }
        private void textBoxDir_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
                if (Directory.Exists(files[0]))
                {
                    ((TextBox)sender).Text = files[0];
                }
                else
                {
                    MessageBox.Show("File object dropped is not an extant directory", "Directory Synchronizer: Unexpected File Object", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                }
            }
        }
        private void textBoxDirInput_TextChanged(object sender, EventArgs e)
        {
            timerInputVerification.Enabled = true;
        }
        private void timerInputVerification_Tick(object sender, EventArgs e)
        {
            CheckIfSyncReady(null, null);
        }
        private void CheckIfSyncReady(object sender, EventArgs e)
        {
            if (showingadvancedoptions) { return; }
            bool syncready = true;
            string error0 = "Input for file directories cannot be zero length";
            string error1 = "Input must be a directory on a local drive (such as 'C:\\...') or network path (such as '\\\\')";
            string error2 = "Selected input for file directories must already exist as directories in the file system(s)";
            string error3 = "Target directory cannot be a subdirectory of the source directory";
            string sourcedirpath = textBoxSourceDir.Text;
            string targetdirpath = textBoxTargetDir.Text;

            errorProviderDirTextBoxes.SetError(buttonSynchronize, null);

            if (sourcedirpath == string.Empty || targetdirpath == string.Empty)
            { errorProviderDirTextBoxes.SetError(buttonSynchronize, error0); syncready = false; }
            else if (sourcedirpath.Substring(1, 2) != ":\\" && sourcedirpath.Substring(0, 2) != @"\\")
            { errorProviderDirTextBoxes.SetError(buttonSynchronize, error1); syncready = false; }
            else if (targetdirpath.Substring(1, 2) != ":\\" && targetdirpath.Substring(0, 2) != @"\\")
            { errorProviderDirTextBoxes.SetError(buttonSynchronize, error1); syncready = false; }
            else if (!Directory.Exists(sourcedirpath))
            { errorProviderDirTextBoxes.SetError(buttonSynchronize, error2); syncready = false; }
            else if (!Directory.Exists(targetdirpath))
            { errorProviderDirTextBoxes.SetError(buttonSynchronize, error2); syncready = false; }
            else if (targetdirpath.ToUpper().StartsWith(sourcedirpath.ToUpper()))
            { errorProviderDirTextBoxes.SetError(buttonSynchronize, error3); syncready = false; }

            if (syncready)
            { buttonSynchronize.Enabled = (currentstate == State.OptionsSetup); }
            else
            { buttonSynchronize.Enabled = false; }
            timerInputVerification.Enabled = false;
        }

        private void checkBoxPreviewOnly_CheckedChanged(object sender, EventArgs e)
        {
            bool enabled = !checkBoxPreviewOnly.Checked;
            checkBoxIgnoreOverwriteAndDelete.Enabled = enabled;
            checkBoxTagInsteadOfOverwrite.Enabled = enabled;
            checkBoxTagInsteadOfDelete.Enabled = enabled;
        }
        private void checkBoxBasicOptionChanged(object sender, EventArgs e)
        {
            if (showingadvancedoptions) { return; }
            if (checkBoxTagInsteadOfOverwrite.Checked || checkBoxTagInsteadOfDelete.Checked)
            {
                checkBoxIgnoreOverwriteAndDelete.Checked = false;
                checkBoxIgnoreOverwriteAndDelete.Enabled = false;
            }
            else
            {
                checkBoxIgnoreOverwriteAndDelete.Enabled = true;
            }
        }
        private void checkBoxIgnoreOverwriteAndDelete_CheckedChanged(object sender, EventArgs e)
        {
            checkBoxTagInsteadOfDelete.Enabled = !checkBoxIgnoreOverwriteAndDelete.Checked;
            checkBoxTagInsteadOfOverwrite.Enabled = !checkBoxIgnoreOverwriteAndDelete.Checked;
        }

        private void dataGridViewSyncResults_DoubleClick(object sender, EventArgs e)
        {
            if (dataGridViewSyncResults.SelectedRows.Count == 1)
            {
                string workstring = dataGridViewSyncResults.SelectedRows[0].Cells[1].Value.ToString();
                ProcessStartInfo psi = new ProcessStartInfo("explorer.exe", workstring);
                Process p = new Process();
                p.StartInfo = psi;
                p.Start();
            }
        }

        public void UpdateProgress(string argformattedupdatetext, long argfileprogress, long argfilecount)
        {
            if (labelProgressMessage.InvokeRequired)
            {
                try
                {
                    ProgressUpdateCrossThreadDelegate upd = new ProgressUpdateCrossThreadDelegate(UpdateProgress);
                    this.Invoke(upd, new object[] { argformattedupdatetext, argfileprogress, argfilecount });
                }
                catch (ObjectDisposedException) { }
            }
            else
            {
                int ints = 0;
                int max = 0;
                if (argfileprogress > int.MaxValue)
                {
                    while (argfileprogress > int.MaxValue)
                    {
                        argfileprogress = argfileprogress - int.MaxValue;
                        ints++;
                    }
                }
                if (argfilecount > int.MaxValue)
                {
                    while (argfilecount > int.MaxValue)
                    {
                        argfilecount = argfilecount - int.MaxValue;
                        max++;
                    }
                }

                progressBarSynchronization.Maximum = (int)argfilecount;
                progressBarSynchronization.Value = (int)argfileprogress;
                labelProgressMessage.Text = String.Format(argformattedupdatetext, argfileprogress, argfilecount);
            }
        }
        public delegate void FinishedProcessDelegate();
        public void ProcessFinished()
        {
            if (this.InvokeRequired)
            {
                FinishedProcessDelegate sfd = new FinishedProcessDelegate(ProcessFinished);
                this.Invoke(sfd, null);
            }
            else
            {
                currentstate = State.SynchronizationCompleted;
                dataGridViewSyncResults.DataSource = directorysynchronizer.syncresultsDS;
                UpdateRefreshFormControls();
                directorysynchronizer.Dispose();
            }
        }

        public void ShowOptionsFormAdjacentTo(Form argAdjacentForm)
        {
            Hide();
            Left = argAdjacentForm.Right + 10;
            Top = (Screen.FromHandle(argAdjacentForm.Handle).Bounds.Height - Height) / 2;
            Show();
        }
        internal void ChildHTMLDisplayFormClosed()
        {
            childhtmldisplayform = null;
        }

        private DirSyncOptions GetCurrentOptionsSetup()
        {
            DirSyncOptions returndirsyncoptions = new DirSyncOptions();
            returndirsyncoptions.CopyAttributes = ctrlAdvancedOptionsOverlay.checkBoxCopyFileAttributes.Checked;
            returndirsyncoptions.IgnoreOverwriteAndDelete = checkBoxIgnoreOverwriteAndDelete.Checked;
            returndirsyncoptions.PreviewOnly = checkBoxPreviewOnly.Checked;
            returndirsyncoptions.DoNotRecurse = ctrlAdvancedOptionsOverlay.checkBoxDoNotRecurse.Checked;
            returndirsyncoptions.SourceDirectory = textBoxSourceDir.Text;
            returndirsyncoptions.SuppressDataGridResultsDisplay = ctrlAdvancedOptionsOverlay.checkBoxSuppressDatagrid.Checked;
            returndirsyncoptions.TagCopyNotOldFile = ctrlAdvancedOptionsOverlay.checkBoxTagSourceNotExistingFile.Checked;
            returndirsyncoptions.TagInsteadOfDelete = checkBoxTagInsteadOfDelete.Checked;
            returndirsyncoptions.TagInsteadOfOverwrite = checkBoxTagInsteadOfOverwrite.Checked;
            returndirsyncoptions.TargetDirectory = textBoxTargetDir.Text;
            return returndirsyncoptions;
        }
        private void LoadOptionsSetupFromObject(DirSyncOptions argDirSyncOptions)
        {
            ctrlAdvancedOptionsOverlay.checkBoxCopyFileAttributes.Checked = argDirSyncOptions.CopyAttributes;
            checkBoxIgnoreOverwriteAndDelete.Checked = argDirSyncOptions.IgnoreOverwriteAndDelete;
            checkBoxPreviewOnly.Checked = argDirSyncOptions.PreviewOnly;
            ctrlAdvancedOptionsOverlay.checkBoxDoNotRecurse.Checked = argDirSyncOptions.DoNotRecurse;
            textBoxSourceDir.Text = argDirSyncOptions.SourceDirectory;
            ctrlAdvancedOptionsOverlay.checkBoxSuppressDatagrid.Checked = argDirSyncOptions.SuppressDataGridResultsDisplay;
            ctrlAdvancedOptionsOverlay.checkBoxTagSourceNotExistingFile.Checked = argDirSyncOptions.TagCopyNotOldFile;
            checkBoxTagInsteadOfDelete.Checked = argDirSyncOptions.TagInsteadOfDelete;
            checkBoxTagInsteadOfOverwrite.Checked = argDirSyncOptions.TagInsteadOfOverwrite;
            textBoxTargetDir.Text = argDirSyncOptions.TargetDirectory;
        }

        internal void UpdateRefreshFormControls()
        {
            switch (currentstate)
            {
                case State.OptionsSetup:
                    buttonBrowseForDir1.Enabled = true;
                    buttonBrowseForDir2.Enabled = true;
                    textBoxSourceDir.ReadOnly = false;
                    textBoxTargetDir.ReadOnly = false;
                    checkBoxPreviewOnly.Enabled = true;
                    panelBelowCenterTop.Visible = false;
                    dataGridViewSyncResults.Enabled = false;
                    buttonCancelSync.Visible = false;
                    buttonResetSynchronizer.Visible = false;
                    licenseToolStripMenuItem.Enabled = true;
                    break;
                case State.Synchronizing:
                    buttonBrowseForDir1.Enabled = false;
                    buttonBrowseForDir2.Enabled = false;
                    textBoxSourceDir.ReadOnly = true;
                    textBoxTargetDir.ReadOnly = true;
                    checkBoxPreviewOnly.Enabled = false;
                    checkBoxTagInsteadOfDelete.Enabled = false;
                    checkBoxTagInsteadOfOverwrite.Enabled = false;
                    checkBoxIgnoreOverwriteAndDelete.Enabled = false;
                    panelBelowCenterTop.Visible = true;
                    dataGridViewSyncResults.Enabled = false;
                    buttonCancelSync.Visible = true;
                    buttonSynchronize.Visible = false;
                    licenseToolStripMenuItem.Enabled = false;
                    break;
                case State.SynchronizationCanceled:
                    buttonBrowseForDir1.Enabled = true;
                    buttonBrowseForDir2.Enabled = true;
                    buttonSynchronize.Enabled = false;
                    textBoxSourceDir.ReadOnly = false;
                    textBoxTargetDir.ReadOnly = false;
                    checkBoxPreviewOnly.Enabled = true;
                    checkBoxTagInsteadOfDelete.Enabled = true;
                    checkBoxTagInsteadOfOverwrite.Enabled = true;
                    checkBoxIgnoreOverwriteAndDelete.Enabled = true;
                    panelBelowCenterTop.Visible = true;
                    dataGridViewSyncResults.Enabled = false;
                    buttonCancelSync.Visible = false;
                    buttonSynchronize.Visible = true;
                    buttonResetSynchronizer.Visible = true;
                    licenseToolStripMenuItem.Enabled = true;
                    break;
                case State.SynchronizationCompleted:
                    buttonBrowseForDir1.Enabled = false;
                    buttonBrowseForDir2.Enabled = false;
                    buttonSynchronize.Enabled = false;
                    textBoxSourceDir.ReadOnly = true;
                    textBoxTargetDir.ReadOnly = true;
                    checkBoxPreviewOnly.Enabled = true;
                    checkBoxTagInsteadOfDelete.Enabled = true;
                    checkBoxTagInsteadOfOverwrite.Enabled = true;
                    checkBoxIgnoreOverwriteAndDelete.Enabled = true;
                    panelBelowCenterTop.Visible = true;
                    dataGridViewSyncResults.Enabled = true;
                    buttonCancelSync.Visible = false;
                    buttonSynchronize.Visible = true;
                    buttonResetSynchronizer.Visible = true;
                    licenseToolStripMenuItem.Enabled = true;
                    break;
                default:
                    break;
            }
            dataGridViewSyncResults.Visible = !ctrlAdvancedOptionsOverlay.checkBoxSuppressDatagrid.Checked;
            Refresh();
        }
        public void AdvancedOptionsControlClosed()
        {
            ctrlAdvancedOptionsOverlay.Visible = false;
            dataGridViewSyncResults.ColumnHeadersVisible = true;
            RecursiveEnableDisable(this, true);
            dataGridViewSyncResults.Visible = !ctrlAdvancedOptionsOverlay.checkBoxSuppressDatagrid.Checked;
            showingadvancedoptions = false;
        }
        private void RecursiveEnableDisable(Control argControl, bool argEnable)
        {
            bool ignoresubcontrols = false;
            if (!(argControl is Panel))
            {
                bool applytoargcontrol = true;
                for (int iii = 0; iii < EnableDisableIgnoreControls.Length; iii++)
                {
                    if (EnableDisableIgnoreControls[iii] == argControl)
                    {
                        applytoargcontrol = false;
                        ignoresubcontrols = EnableDisableIgnoreSUBcontrols[iii];
                        break;
                    }
                }
                if (applytoargcontrol) { argControl.Enabled = argEnable; }
            }
            if (!ignoresubcontrols)
            {
                foreach (Control c in argControl.Controls)
                {
                    RecursiveEnableDisable(c, argEnable);
                }
            }
        }
        private bool ConfirmSyncCancel()
        {
            if (MessageBox.Show("Are you sure you want to cancel?", "Confirm Cancel", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == System.Windows.Forms.DialogResult.Yes)
            {
                return true;
            }
            return false;
        }

    }
}
